package com.brayan.webapp.repository;

import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Root;

import com.brayan.webapp.model.Pub;
import com.brayan.webapp.model.PubThread;
import com.brayan.webapp.model.PubThread_;
import com.brayan.webapp.model.Pub_;

@Stateless
public class PubRepository {

	@PersistenceContext(unitName = "ccms")
	EntityManager em;

	public Pub getPubById(Long pubId) {
		Pub pub = em.find(Pub.class, pubId);
		return pub;
	}

	/**
	 * Retrieve all active Pubs that match a given category.
	 * 
	 * @param categoryId
	 *            The category to match
	 * @return A list of active publications which match the criterion - or null
	 *         if no match occurs.
	 */
	public List<Pub> getPubsByCategory(Long categoryId) {
		CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
		CriteriaQuery<Pub> criteriaQuery = criteriaBuilder
				.createQuery(Pub.class);
		Root<Pub> rootPub = criteriaQuery.from(Pub.class);
		criteriaQuery.select(rootPub)
				.where(criteriaBuilder.equal(rootPub.get(Pub_.pubCategory),
						categoryId));

		criteriaQuery.orderBy(
				criteriaBuilder.desc(rootPub.get(Pub_.dateModified)),
				criteriaBuilder.desc(rootPub.get(Pub_.dateCreated)));

		TypedQuery<Pub> typedQuery = em.createQuery(criteriaQuery);
		List<Pub> pubList = typedQuery.getResultList();

		return pubList;
	}

	/**
	 * Get all Pubs related to a thread.
	 * 
	 * @param threadId
	 *            The related thread id.
	 * @return A list of pubs.
	 */
	public List<Pub> getPubsByThread(Long threadId) {

		CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
		CriteriaQuery<Pub> criteriaQuery = criteriaBuilder
				.createQuery(Pub.class);

		// Create the FROM
		Root<PubThread> rootPubThread = criteriaQuery.from(PubThread.class);
		// Create the WHERE
		criteriaQuery.where(criteriaBuilder.equal(
				rootPubThread.get(PubThread_.id), threadId));
		// Create the JOIN
		Join<PubThread, Pub> join = rootPubThread.join(PubThread_.pups);
		// Create the SELECT, at last
		CriteriaQuery<Pub> cq = criteriaQuery.select(join);
		// sort
		criteriaQuery.orderBy(
				criteriaBuilder.desc(join.get(Pub_.dateModified)),
				criteriaBuilder.desc(join.get(Pub_.dateCreated)));

		TypedQuery<Pub> typedQuery = em.createQuery(criteriaQuery);
		List<Pub> pubList = typedQuery.getResultList();
		return pubList;
	}

	public void updatePub(Pub pub) {
		// update the entity
		em.merge(pub);
	}

	/**
	 * If certain, that no such pub exists, user insert (using persist()). It is
	 * faster than the merge function.
	 * 
	 * @param pub
	 */
	public void insertPub(Pub pub) {
		em.persist(pub);
	}

}
